package com.ratta.supernote.note.plugincore.utils;

import android.graphics.Bitmap;
import android.os.Environment;
import android.os.StatFs;
import android.text.TextUtils;
import android.util.Log;

import com.facebook.react.bridge.Promise;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class FileUtils {
    private static final String TAG = "FileUtils";
    private static final int FILE_HEADER_SIZE = 12;

    public static String readFile(String filePath) {
        try {
            // Open file input stream
            FileInputStream fis = new FileInputStream(filePath);

            // Read file content
            InputStreamReader isr = new InputStreamReader(fis);
            BufferedReader bufferedReader = new BufferedReader(isr);
            StringBuilder sb = new StringBuilder();
            String line;

            while ((line = bufferedReader.readLine()) != null) {
                sb.append(line).append("\n");
            }

            // Close streams
            bufferedReader.close();
            isr.close();
            fis.close();

            // File content
            String fileContents = sb.toString();
            return fileContents;
        } catch (FileNotFoundException e) {
            // File not found exception handling
            e.printStackTrace();
        } catch (IOException e) {
            // IO exception handling
            e.printStackTrace();
        }
        return null;
    }

    public static boolean deleteDir(String dirPath) {
        File dir = new File(dirPath);
        return deleteDir(dir);

    }

    public static boolean deleteDir(File dir) {
        if (!dir.exists()) {
            return true;
        }
        if (dir.isDirectory()) {
            String[] children = dir.list();
            for (int i = 0; i < children.length; i++) {
                boolean success = deleteDir(new File(dir, children[i]));
                if (!success) {
                    return false;
                }
            }
        }
        return dir.delete();

    }

    public static boolean deleteFile(String filePath) {
        if (TextUtils.isEmpty(filePath)) {
            return true;
        }
        File file = new File(filePath);
        if (file.exists()) {
            return file.delete();
        }
        return true;
    }

    public static boolean moveDirectory(String sourcePath, String destPath) {
        return moveDirectory(new File(sourcePath), new File(destPath));
    }

    public static boolean moveDirectory(File sourceDir, File destDir) {
        // Ensure source directory exists
        if (!sourceDir.exists() || !sourceDir.isDirectory()) {
            return false;
        }

        // If target directory doesn't exist, try to create it
        if (!destDir.exists()) {
            if (!destDir.mkdirs()) {
                return false;
            }
        }

        // Get all files and directories under source directory
        File[] files = sourceDir.listFiles();
        if (files == null) {
            return false;
        }

        for (File file : files) {
            File destFile = new File(destDir, file.getName());
            // If file is directory, move recursively; otherwise, simply rename the file
            if (file.isDirectory()) {
                moveDirectory(file, destFile);
            } else {
                if (!file.renameTo(destFile)) {
                    return false;
                }
            }
        }

        // Finally delete the empty source directory
        return sourceDir.delete();
    }

    /**
     * Verify if file is a zip file
     * @param zipPath
     */
    public static boolean checkZip(String zipPath) {
        if (TextUtils.isEmpty(zipPath)) {
            return false;
        }
        return zipPath.endsWith(".zip");
    }

    public static boolean checkSnx(String snxPath) {
        if (TextUtils.isEmpty(snxPath)) {
            return false;
        }
        return snxPath.endsWith(".snplg");
    }

    /**
     * Extract file
     * @throws IOException
     */
    public static void unZip(String zipFilePath, String targetPath) throws IOException {
        File destDir = new File(targetPath);
        if (!destDir.exists()) {
            destDir.mkdirs();
        }
        File file = new File(zipFilePath);
        FileInputStream fis = new FileInputStream(file);
        ZipInputStream zis = new ZipInputStream(new BufferedInputStream(fis));
        String targetBasePath = targetPath;
        unzip(zis, targetBasePath);
    }

    public static void unzip(ZipInputStream zis, String targetPath) throws IOException {
        ZipEntry entry = zis.getNextEntry();
        if (entry != null) {
            String entryName = entry.getName();
            File file = new File(targetPath + File.separator + entry.getName());
            if (entry.isDirectory()) {
                // Empty directory may exist
                if (!file.exists()) {
                    file.mkdirs();
                }
                unzip(zis, targetPath);
            } else {
                File parentFile = file.getParentFile();
                if (parentFile != null && !parentFile.exists()) {
                    parentFile.mkdirs();
                }
                FileOutputStream fos = null;
                try {
                    fos = new FileOutputStream(file);// Parent path must exist when creating file with output stream
                    int len = 0;
                    byte[] buf = new byte[1024];
                    while ((len = zis.read(buf)) != -1) {
                        fos.write(buf, 0, len);
                    }
                    fos.flush();

                } catch (Exception ex) {
                } finally {
                    if (fos != null) {
                        fos.close();
                    }
                }
                zis.closeEntry();
                unzip(zis, targetPath);
            }
        }
    }

    /// Get filename with extension
    public static String getFileNameSuffix(String path) {
        boolean b = path.contains("/");
        int start = 0;
        if (b) {
            start = path.lastIndexOf("/");
        }
        if (start != -1) {
            if (b) {
                return path.substring(start + 1);
            } else {
                return path.substring(start);
            }
        } else {

            return null;
        }
    }

    public static String getFileName(String path) {

        boolean b = path.contains("/");
        int start = 0;
        if (b) {
            start = path.lastIndexOf("/");
        }

        int end = path.lastIndexOf(".");

        if (start != -1 && end != -1) {

            if (b) {
                return path.substring(start + 1, end);
            } else {
                return path.substring(start, end);
            }

        } else {

            return null;
        }
    }

    public static String getImageFormat(String filePath) {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(filePath);
            byte[] fileHeader = new byte[FILE_HEADER_SIZE];
            if (fis.read(fileHeader, 0, FILE_HEADER_SIZE) != -1) {
                String fileHeaderStr = new String(fileHeader, 0, FILE_HEADER_SIZE);
                if (isJPEG(fileHeader)) {
                    Log.i(TAG, "getImageFormat: JPEG");
                    return "JPEG";
                } else if (isPNG(fileHeader)) {
                    Log.i(TAG, "getImageFormat: PNG");
                    return "PNG";
                } else if (fileHeaderStr.startsWith("RIFF") && fileHeaderStr.endsWith("WEBP")) {
                    Log.i(TAG, "getImageFormat: WEBP");
                    return "WEBP";
                }
//                else if (fileHeaderStr.startsWith(TIFF_HEADER)) {
//                    Log.i(TAG, "getImageFormat: TIFF");
//                    return "TIFF";
//                } else if (fileHeaderStr.startsWith(SVG_HEADER)) {
//                    Log.i(TAG, "getImageFormat: SVG");
//                    return "SVG";
//                } else if (startsWith(fileHeader, "GIF87a".getBytes()) || startsWith(fileHeader, "GIF89a".getBytes())) {
//                    Log.i(TAG, "getImageFormat: GIF");
//                    return "GIF";
//                } else if (fileHeaderStr.startsWith(BMP_HEADER)) {
//                    Log.i(TAG, "getImageFormat: BMP");
//                    return "BMP";
//                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return "";
    }

    private static boolean isJPEG(byte[] magicNumber) {
        return magicNumber[0] == (byte) 0xFF && magicNumber[1] == (byte) 0xD8;
    }

    private static boolean isPNG(byte[] magicNumber) {
        byte[] pngMagicNumber = {(byte) 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
        for (int i = 0; i < pngMagicNumber.length; i++) {
            if (magicNumber[i] != pngMagicNumber[i]) {
                return false;
            }
        }
        return true;
    }

    /**
     * Get bundle filename from directory
     * @param dirPath
     * @return
     */
    public static String getBundleFileName(String dirPath) {
        if (TextUtils.isEmpty(dirPath)) {
            return null;
        }
        File dir = new File(dirPath);
        // Directory cannot exist
        if (!dir.exists()) {
            return null;
        }
        // Get all files and directories under source directory
        File[] files = dir.listFiles();
        // No files in directory
        if (files == null) {
            return null;
        }

        for (File file : files) {
            if (file.isFile()) {
                String fileName = file.getName();
                if (fileName.endsWith(".bundle")) {
                    return fileName;
                }
            }
        }
        return null;
    }

    public static boolean isFileExists(String filePath) {
        if (TextUtils.isEmpty(filePath)) {
            return false;
        }
        File file = new File(filePath);
        return file.exists();
    }

    public static void copyFile(String sourcePath, String destinationPath) throws IOException {
        FileInputStream inputStream = null;
        FileOutputStream outputStream = null;
        try {
            inputStream = new FileInputStream(sourcePath);
            outputStream = new FileOutputStream(destinationPath);

            byte[] buffer = new byte[1024];
            int length;
            while ((length = inputStream.read(buffer)) > 0) {
                outputStream.write(buffer, 0, length);
            }
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
            if (outputStream != null) {
                outputStream.close();
            }
        }
    }

    public static String getFileMD5(String filePath) {
        MessageDigest digest;
        try {
            digest = MessageDigest.getInstance("MD5");
            InputStream is = new FileInputStream(filePath);

            byte[] buffer = new byte[1024];
            int read = 0;
            while ((read = is.read(buffer)) != -1) {
                digest.update(buffer, 0, read);
            }
            is.close();

            byte[] md5Bytes = digest.digest();
            StringBuilder hexString = new StringBuilder();
            for (byte md5Byte : md5Bytes) {
                hexString.append(Integer.toString((md5Byte & 0xFF) + 0x100, 16).substring(1));
            }
            return hexString.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static boolean saveBitmapToPng(Bitmap bitmap, String filePath) {
        try {
            FileOutputStream fileOutputStream = new FileOutputStream(filePath);
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream);
            fileOutputStream.flush();
            fileOutputStream.close();
            return true;
        } catch (Exception e) {
            e.printStackTrace();

        }
        return false;
    }

    /**
     * Get parent directory path of file
     * @param filePath
     * @return
     */
    public static String getParentDirPath(String filePath) {
        if (TextUtils.isEmpty(filePath)) {
            return "";
        }
        String dirPath = filePath.substring(0, filePath.lastIndexOf("/"));
        return dirPath;
    }

    public static void mkdir(String dirPath) {
        File dir = new File(dirPath);
        if (!dir.exists()) {
            Log.i(TAG, "mkdir dir no:");
            dir.mkdirs();
        }
    }

    public static boolean saveTextToFile(String filePath, String text) {
        deleteFile(filePath);
        FileOutputStream outputStream = null;
        boolean isSucceed = false;

        try {
            String dirPath = getParentDirPath(filePath);
            Log.i(TAG, "saveTextToFile dirPath:" + dirPath);
            mkdir(dirPath);
            outputStream = new FileOutputStream(filePath);
            outputStream.write(text.getBytes());

        } catch (IOException e) {
            e.printStackTrace();

        } finally {
            try {
                if (outputStream != null) {
                    outputStream.close();
                    isSucceed = true;
                }

            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return isSucceed;

    }

    public static long getStorageAvailableSpace() {
        String absolutePath = Environment.getExternalStorageDirectory().getAbsolutePath();
        StatFs statFs = new StatFs(absolutePath);
        long blockSize = statFs.getBlockSizeLong();
        long availCount = statFs.getAvailableBlocksLong();
        long availableSize = availCount * blockSize;
        return availableSize;
    }


}
